#include "unitest.h"
#include <libucontext/bits.h>
#include <libucontext/libucontext.h>

class UcontextUnitest : public testing::Test {
protected:
    void SetUp() override {
    }

    void TearDown() override {
    }
};

TEST_F(UcontextUnitest, get_set_context) {
    int32_t counter = 0;
    libucontext_ucontext context{};
    libucontext_getcontext(&context);
    ++counter;
    if (counter < 5) {
        libucontext_setcontext(&context);
    }
    EXPECT_EQ(counter, 5);
}

void target_function(const libucontext_ucontext* exit_point, int* a, int* b, int* c, int* d, int* e, int* f, int* g, int* h) {
    *a = 1;
    *b = 2;
    *c = 3;
    *d = 4;
    *e = 5;
    *f = 6;
    *g = 7;
    *h = 8;
    libucontext_setcontext(exit_point);
}

TEST_F(UcontextUnitest, make_set_swap_context) {
    const std::size_t stack_size = 64*1024;
    auto stack = std::make_unique<uint8_t[]>(stack_size);
    EXPECT_NE(stack, nullptr);
    int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
    libucontext_ucontext target_context{};
    libucontext_ucontext current_context{};
    libucontext_getcontext(&target_context);
    target_context.uc_stack.ss_sp = stack.get();
    target_context.uc_stack.ss_size = stack_size;
    target_context.uc_link = &current_context;
    libucontext_makecontext(&target_context, (void (*)()) target_function, 9, &current_context, &a, &b, &c, &d, &e, &f, &g, &h);
    libucontext_swapcontext(&current_context, &target_context);
    EXPECT_EQ(a, 1);
    EXPECT_EQ(b, 2);
    EXPECT_EQ(c, 3);
    EXPECT_EQ(d, 4);
    EXPECT_EQ(e, 5);
    EXPECT_EQ(f, 6);
    EXPECT_EQ(g, 7);
    EXPECT_EQ(h, 8);
}



